package RobotSwarm;

import java.util.*;


import repast.simphony.context.Context;
import repast.simphony.context.space.continuous.ContinuousSpaceFactory;
import repast.simphony.context.space.continuous.ContinuousSpaceFactoryFinder;
import repast.simphony.context.space.grid.GridFactoryFinder;
import repast.simphony.dataLoader.ContextBuilder;
import repast.simphony.random.RandomHelper;
import repast.simphony.space.continuous.BouncyBorders;
import repast.simphony.space.continuous.ContinuousSpace;
import repast.simphony.space.continuous.NdPoint;
import repast.simphony.space.continuous.RandomCartesianAdder;
import repast.simphony.space.grid.Grid;
import repast.simphony.space.grid.GridBuilderParameters;
import repast.simphony.space.grid.SimpleGridAdder;
import repast.simphony.valueLayer.GridValueLayer;

public class CntxtBuilder implements ContextBuilder<Object>{
	
	/*****************************************************************************************************************************************/
	final static int LeaderCount=3;
	final static int FollowerCount=5;
	final int TargetCount=5; 
	final int ObstacleCount=20; //Make sure that you change the obstacle_count if the Count is >100
	final int countdown=5; //Time after which the no-network area changes
	final double probability=1; //Probability of having yes-network area
	final int leaderradius=2; //intial radius of the circle made 
	final double pl_lowerbound=2;
	final double pl_upperbound=6;
	final double pl_power=2;
	final double memory_weight_probability=.1;
	final double repulsionAng=Math.PI/2;
	final static int TimeDelay = 3;
	final static boolean flag = false;
	final static int randomTimeDelay = 0;
	final static int timeCount = 0;
	
	/********************************************************************************************************************8*********************/
	
	int var=0;
	public Hashtable<Integer,Integer>leaderx=new Hashtable<Integer,Integer>();
	public Hashtable<Integer,Integer>leadery=new Hashtable<Integer,Integer>();
	public Hashtable<Integer,Integer>targetx=new Hashtable<Integer,Integer>();
	public Hashtable<Integer,Integer>targety=new Hashtable<Integer,Integer>();
	static Hashtable<Integer,Integer>targetCountdown=new Hashtable<Integer,Integer>();
	
	@Override
	public Context build(Context<Object> context) {
		 
		final int LeaderSpeed=2;
		final double FollowerSpeed=LeaderSpeed;

		
		final int environmentSize=50;	
		
		context.setId("RobotSwarm"); //Don't modify it
		
		//The target and leader moves in a continuous space
		ContinuousSpaceFactory spaceFactory=ContinuousSpaceFactoryFinder.createContinuousSpaceFactory(null);
		ContinuousSpace<Object> space=spaceFactory.createContinuousSpace("space", context, new RandomCartesianAdder<Object>(), new BouncyBorders(), environmentSize, environmentSize);
		
		//The grid is overlaid on the continuous space to get neighbours
		repast.simphony.context.space.grid.GridFactory gridFactory=GridFactoryFinder.createGridFactory(null);
		Grid<Object> grid1=gridFactory.createGrid("grid", context, new GridBuilderParameters<Object>(new repast.simphony.space.grid.BouncyBorders(), new SimpleGridAdder<Object>(), true, environmentSize, environmentSize));
			
		//add targets to the context
		for(int i=0; i<TargetCount;){
			Target target = new Target(space, grid1);
			context.add(target);
			double x=(double)(Math.random()*(environmentSize-0.1));
			double y=(double)(Math.random()*(environmentSize-0.1));
			if(!targetx.containsValue((int)x) || !targety.containsValue((int)y))
			{
			space.moveTo(target,x ,y);
			
			targetx.put(i,(int)x);
			targety.put(i,(int)y);
			
			int randomCount = (int)(150.0*Math.random());
			
			targetCountdown.put(target.hashCode(),randomCount);
			
			++i;
			}
			
			if (var==TargetCount){
				context.remove(target);
			}
		}
		
		//add leaders to the context
		double angleStep=360/LeaderCount;
		double angle=0;
		
		for(int i=0; i<FollowerCount*LeaderCount; i++){
			Followers follow = new Followers(space, grid1, FollowerSpeed,i+1,true);
			context.add(follow);
			space.moveTo(follow, (double)(7*Math.random()+(environmentSize/2)),(double)(7*Math.random()+(environmentSize/2)));
			
		}
		for(int i=0; i<LeaderCount;)
		{
			double x=(leaderradius*Math.cos(Math.toRadians(angle)))+environmentSize/2;
			double y=(leaderradius*Math.sin(Math.toRadians(angle)))+environmentSize/2;
			
			angle+=angleStep;
			
			int energy= RandomHelper.nextIntFromTo(1,2);
			if(!targetx.containsValue((int)x) || !targety.containsValue((int)y))
			{
				if(!leaderx.containsValue((int)x) || !leadery.containsValue((int)y))
				{
					
					
					Leader leader =new Leader(space, grid1, energy, LeaderSpeed,i+1,pl_lowerbound,pl_upperbound,pl_power,ObstacleCount,memory_weight_probability,repulsionAng, flag, randomTimeDelay, timeCount);
					context.add(leader);
					space.moveTo(leader,x,y);
		
					leaderx.put(i,(int)x);
					leadery.put(i,(int)y);
					++i;
					
					
				}
				else
				{
					continue;
				}
			}
			else
			{
				continue;
			}
			
			}
		
		//Adding obstacles to the context
		
		for(int i=0; i<ObstacleCount;)
		{
			Obstacle obstacle = new Obstacle(space, grid1);
			context.add(obstacle);
			double x=(double)(Math.random()*(environmentSize-1));
			double y=(double)(Math.random()*(environmentSize-1));
			if(!targetx.containsValue((int)x) || !targety.containsValue((int)y))
			{
				if(!leaderx.containsValue((int)x) || !leadery.containsValue((int)y))
				{
					space.moveTo(obstacle, x,y);
					++i;
				}
				else
				{
					continue;
				}
			}
			else
			{
				continue;
			}
		}
	
		for(Object obj:context)  //Give grid locations to the targets and leaders from their space locations
		{
			NdPoint pt=space.getLocation(obj);
			grid1.moveTo(obj, (int)pt.getX(), (int)pt.getY());
		}	
		
		GridValueLayer vl = new GridValueLayer("Network Field", true,
				new repast.simphony.space.grid.WrapAroundBorders(),environmentSize,environmentSize);
		
		context.addValueLayer(vl);

		for (int i=0; i<environmentSize; i++){
			for (int j=0; j<environmentSize; j++){
				Grass grass = new Grass(i,j,countdown,probability);  // create a new grass
				context.add(grass);
                grid1.moveTo(grass, i, j);
			}
		}

		return context;
	}

}
